package com.ndhutu.ee.util.map;

public class GISUtil {
	public final static int r = 6371000;

	// private static double toRad(double degree) {
	// return degree * Math.PI / 180;
	// }
	//
	// /**
	// * 根据经纬度计算距离
	// *
	// * @param fromLon
	// * @param fromLat
	// * @param toLon
	// * @param toLat
	// * @return
	// */
	// public static double sphereDistance(double fromLon, double fromLat,
	// double toLon, double toLat) {
	//
	// double a = Math.pow(Math.sin(toRad(toLat - fromLat) / 2), 2)
	// + (Math.pow(Math.sin(toRad(toLon - fromLon) / 2), 2)
	// * Math.cos(toRad(fromLat)) * Math.cos(toRad(toLat)));
	// double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
	//
	// return r * c;
	// }

	private final static double PI = 3.14159265358979323; // 圆周率
	private final static double R = 6371229; // 地球的半径

	/**
	 * 计算两个坐标之间的距离
	 * 
	 * @param longt1
	 * @param lat1
	 * @param longt2
	 * @param lat2
	 * @return
	 */
	public static double getDistance(double longt1, double lat1, double longt2,
			double lat2) {
		double x, y, distance;
		x = (longt2 - longt1) * PI * R
				* Math.cos(((lat1 + lat2) / 2) * PI / 180) / 180;
		y = (lat2 - lat1) * PI * R / 180;
		distance = Math.hypot(x, y);
		return distance;
	}

	/**
	 * 根据中心点和距离返回矩形框
	 * 
	 * @param lng
	 * @param lat
	 * @param distance
	 * @return
	 */
	public static double[] getRectangle(double lng, double lat, double distance) {
		float delta = 111199; // 大约是111000m/1¡ã
		if (lng != 0 && lat != 0) {
			double lng1 = lng - distance
					/ Math.abs(Math.cos(Math.toRadians(lat)) * delta);
			double lng2 = lng + distance
					/ Math.abs(Math.cos(Math.toRadians(lat)) * delta);
			double lat1 = lat - (distance / delta);
			double lat2 = lat + (distance / delta);
			return new double[] { lng1, lat1, lng2, lat2 };
		} else {// TODO ZHCH 等于0时的计算公式
			double lng1 = lng - distance / delta;
			double lng2 = lng + distance / delta;
			double lat1 = lat - (distance / delta);
			double lat2 = lat + (distance / delta);
			return new double[] { lng1, lat1, lng2, lat2 };
		}
	}

	/**
	 * 返回右上的矩形
	 * 
	 * @param lng
	 * @param lat
	 * @param distance
	 * @return
	 */
	public static double[] getRightUpRectangle(double lng, double lat,
			double distance) {
		float delta = 111000; // 大约是111000m/1¡ã

		double lng2 = lng + distance
				/ Math.abs(Math.cos(Math.toRadians(lat)) * delta);

		double lat2 = lat - (distance / delta);
		return new double[] { lng2, lat2 };

	}

	/**
	 * 返回右上角的经度
	 * 
	 * @param lng
	 * @param lat
	 * @param distance
	 * @return
	 */
	public static double getLongt(double lng, double lat, double distance) {
		float delta = 111199; // 大约是111000m/1¡ã

		double lng2 = lng + distance
				/ Math.abs(Math.cos(Math.toRadians(lat)) * delta);
		return lng2;

	}

	/**
	 * 返回右上角的纬度
	 * 
	 * @param lng
	 * @param lat
	 * @param distance
	 * @return
	 */
	public static double getLat(double lng, double lat, double distance) {
		float delta = 111199; // 大约是111000m/1¡ã
		double lat2 = lat + (distance / delta);
		return lat2;

	}

	// 坐标系转换
	public static final String BAIDU_LBS_TYPE = "bd09ll";

	public static double pi = 3.1415926535897932384626;
	public static double a = 6378245.0;
	public static double ee = 0.00669342162296594323;

	/**
	 * 84 to 火星坐标系 (GCJ-02) World Geodetic System ==> Mars Geodetic System
	 * 
	 * @param lat
	 * @param lon
	 * @return
	 */
	public static Gps gps84_To_Gcj02(double lat, double lon) {
		if (outOfChina(lat, lon)) {
			return null;
		}
		double dLat = transformLat(lon - 105.0, lat - 35.0);
		double dLon = transformLon(lon - 105.0, lat - 35.0);
		double radLat = lat / 180.0 * pi;
		double magic = Math.sin(radLat);
		magic = 1 - ee * magic * magic;
		double sqrtMagic = Math.sqrt(magic);
		dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
		dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
		double mgLat = lat + dLat;
		double mgLon = lon + dLon;
		return new Gps(mgLat, mgLon);
	}
	/**
	 * 84 to 百度坐标
	 * @param lat
	 * @param lon
	 * @return
	 */
	public static Gps gps84_To_Bd09(double lat, double lon) {
		if (outOfChina(lat, lon)) {
			return null;
		}
		Gps gcj02=gps84_To_Gcj02(lat, lon);
		return gcj02_To_Bd09(gcj02.getLat(),gcj02.getLng());
	}
	/**
	 * * 火星坐标系 (GCJ-02) to 84 * * @param lon * @param lat * @return
	 * */
	public static Gps gcj_To_Gps84(double lat, double lon) {
		Gps gps = transform(lat, lon);
		double lontitude = lon * 2 - gps.getLng();
		double latitude = lat * 2 - gps.getLat();
		return new Gps(latitude, lontitude);
	}

	/**
	 * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 将 GCJ-02 坐标转换成 BD-09 坐标
	 * 
	 * @param gg_lat
	 * @param gg_lon
	 */
	public static Gps gcj02_To_Bd09(double gg_lat, double gg_lon) {
		double x = gg_lon, y = gg_lat;
		double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * pi);
		double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * pi);
		double bd_lon = z * Math.cos(theta) + 0.0065;
		double bd_lat = z * Math.sin(theta) + 0.006;
		return new Gps(bd_lat, bd_lon);
	}

	/**
	 * * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 * * 将 BD-09 坐标转换成GCJ-02 坐标 * * @param
	 * bd_lat * @param bd_lon * @return
	 */
	public static Gps bd09_To_Gcj02(double bd_lat, double bd_lon) {
		double x = bd_lon - 0.0065, y = bd_lat - 0.006;
		double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * pi);
		double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * pi);
		double gg_lon = z * Math.cos(theta);
		double gg_lat = z * Math.sin(theta);
		return new Gps(gg_lat, gg_lon);
	}

	/**
	 * (BD-09)-->84
	 * 
	 * @param bd_lat
	 * @param bd_lon
	 * @return
	 */
	public static Gps bd09_To_Gps84(double bd_lat, double bd_lon) {

		Gps gcj02 = bd09_To_Gcj02(bd_lat, bd_lon);
		Gps map84 = gcj_To_Gps84(gcj02.getLat(), gcj02.getLng());
		return map84;

	}

	public static boolean outOfChina(double lat, double lon) {
		if (lon < 72.004 || lon > 137.8347)
			return true;
		if (lat < 0.8293 || lat > 55.8271)
			return true;
		return false;
	}

	public static Gps transform(double lat, double lon) {
		if (outOfChina(lat, lon)) {
			return new Gps(lat, lon);
		}
		double dLat = transformLat(lon - 105.0, lat - 35.0);
		double dLon = transformLon(lon - 105.0, lat - 35.0);
		double radLat = lat / 180.0 * pi;
		double magic = Math.sin(radLat);
		magic = 1 - ee * magic * magic;
		double sqrtMagic = Math.sqrt(magic);
		dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
		dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
		double mgLat = lat + dLat;
		double mgLon = lon + dLon;
		return new Gps(mgLat, mgLon);
	}

	public static double transformLat(double x, double y) {
		double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
				+ 0.2 * Math.sqrt(Math.abs(x));
		ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
		ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
		ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
		return ret;
	}

	public static double transformLon(double x, double y) {
		double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
				* Math.sqrt(Math.abs(x));
		ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
		ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
		ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0
				* pi)) * 2.0 / 3.0;
		return ret;
	}

	/**
	 * 根据grid的倍数获取gridid
	 * 
	 * @param xGridNum
	 * @param yGridNum
	 * @return
	 */
	public static long getCellID(long xGridNum, long yGridNum) {
		return (long)((long)(xGridNum * 100000) + yGridNum);
	}

	public static void main(String[] args) {
		System.out.println();
		/*double distance = getDistance(Const.START_LONGITUDE,
				Const.START_LATITUDE, 100, Const.START_LATITUDE);
		System.out
				.println(getDistance(
						100, Const.START_LATITUDE,
						getLongt(Const.START_LONGITUDE, Const.START_LATITUDE,
								distance),Const.START_LATITUDE));
		distance = getDistance(Const.START_LONGITUDE,
				Const.START_LATITUDE, Const.START_LONGITUDE, 40);
		System.out
				.println(getDistance(
						Const.START_LONGITUDE, 40,Const.START_LONGITUDE,
						getLat(Const.START_LONGITUDE, Const.START_LATITUDE,
								distance)));
								*/
		Gps  gps=GISUtil.bd09_To_Gcj02(23.1353080000, 113.2707930000);
		System.out.println(gps.getLat()+"-"+gps.getLng());
		// System.out.println(getLat(73.497522, 18.1223380644, 3878358));
	}
}
